package com.label.Web;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.label.Config.Common.Constant;
import com.label.Config.Exception.CustomException;
import com.label.Config.Exception.CustomUnauthorizedException;
import com.label.Config.Logger.LogAnnotation;
import com.label.Config.MyBatis.IdGenerator;
import com.label.Model.Common.ResponseBean;
import com.label.Model.Common.Validation.Del;
import com.label.Model.Common.Validation.Save;
import com.label.Model.Common.Validation.Update;
import com.label.Model.Do.User;
import com.label.Model.Query.TransQuery;
import com.label.Model.Query.UserQuery;
import com.label.Model.Vo.UserAllVo;
import com.label.Model.Vo.UserBaseInfo;
import com.label.Service.UserService;
import com.label.Service.VerificationService;
import com.label.Service.WordService;
import com.label.Utils.Common.AesCipherUtil;
import com.label.Utils.Common.JwtUtil;
import com.label.Utils.Common.RedisUtil;
import com.label.Utils.UserUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping(value = "/user")
@Api(value =  "用户模块",tags = "用户模块")
public class UserController {

    private final static Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private VerificationService verificationService;

    @Resource
    private UserService userService;

    @Resource
    private WordService wordService;

    @Value("${shiro.refreshTokenExpireTime}")
    private String refreshTokenExpireTime;

    @Value("${file.path}")
    public String path;

    @Resource
    @Qualifier("oracleJdbcTemplate")
    private JdbcTemplate oracleJdbc;

    @Resource
    @Qualifier("sparkSqlJdbcTemplate")
    private JdbcTemplate sparkJdbc;


    /**
     * @description 实现对用户发送邮箱验证码
     * @param email
     * @param session
     * @return
     */
    @GetMapping ("/verification")
    @LogAnnotation(module = "验证码登录模块",operator = "获取验证码")
    @ApiOperation(value = "获取验证码",notes = "获取验证码",httpMethod = "GET")
    public ResponseBean sendVerificationCode(@ApiParam(value="email",required=true)@RequestParam("email") String email, HttpSession session){
        String VerificationCode = verificationService.sendVerification(email);
        RedisUtil.setObject(email + "email",email,300);
        RedisUtil.setObject(email + "verificationCode",VerificationCode,300);
        RedisUtil.setObject(email + "count",5,300);
//        session.setAttribute("email",email);
//        session.setAttribute("verificationCode",VerificationCode);
        return new ResponseBean(HttpStatus.OK.value(), "验证码发送成功(Send Verification Success.)", null);
    }

    /**
     * @description 实现验证码登录
     * @param email
     * @param code
     * @param
     * @return
     */
    @PostMapping ("/codeLogin")
    @LogAnnotation(module = "验证码登录模块",operator = "使用验证码登录")
    @ApiOperation(value = "验证码登录",notes = "验证码登录",httpMethod = "POST")
    public ResponseBean verificationCodeLogin(@ApiParam(value="email",required=true)@RequestParam(value = "email") String email,@ApiParam(value="code",required=true)@RequestParam(value = "code") String code,HttpServletResponse httpServletResponse){
        // 从Redis中获取验证码
        String codeInRedis = (String) RedisUtil.getObject(email + "verificationCode");
        // 从Redis中获取请求验证码的邮箱
        String emailInRedis = (String) RedisUtil.getObject(email + "email");
        // 从Redis中获取对比次数
        Integer count = (Integer) RedisUtil.getObject(email + "count");
        // 进行验证码比对
        if (codeInRedis == null || emailInRedis == null ) {
            return new ResponseBean(HttpStatus.INTERNAL_SERVER_ERROR.value(), "未申请验证码(Verification Not Available.)", null);
        }
        if (!count.equals(0)) {
            RedisUtil.setObject(email + "count", --count);
            if ( !codeInRedis.equals(code) || !emailInRedis.equals(email)) {
                return new ResponseBean(HttpStatus.INTERNAL_SERVER_ERROR.value(), "验证码错误(Verification ERROR.)", null);
            }
        }else {
            RedisUtil.delKey(email + "verificationCode");
            RedisUtil.delKey(email + "email");
            RedisUtil.delKey(email + "count");
            return new ResponseBean(HttpStatus.INTERNAL_SERVER_ERROR.value(), "错误次数过多，请重新获取(Too Many ERROR.)", null);
        }
        RedisUtil.delKey(email + "verificationCode");
        RedisUtil.delKey(email + "email");
        RedisUtil.delKey(email + "count");
        // 验证码对比成功 调用原登录接口登录
        return login(verificationService.getLoginInfo(email),httpServletResponse);


    }


    /**
     * 用户登录
     * @param userQuery  包括account和password
     * @return 返回当前登录用户的信息，包括oracle信息和hive信息
     */
    @RequestMapping("/login")

    @LogAnnotation(module = "用户模块",operator = "登录")
    @ApiOperation(value = "登录",notes = "登录",httpMethod = "POST")
    public ResponseBean login(@ApiParam(name="用户对象",value="传入json格式",required=true)@RequestBody UserQuery userQuery, HttpServletResponse httpServletResponse){
        // 直接进行了数据库查询，返回了一个和UserQuery中的account相等的User对象
        User userTemp = userService.getOne(new QueryWrapper<User>().lambda().eq(User::getAccount,userQuery.getAccount()));
        if (userTemp == null) {
            throw new CustomUnauthorizedException("该帐号不存在(The account does not exist.)");
        }
        // 密码进行AES解密
        String key = AesCipherUtil.deCrypto(userTemp.getPassword());
        // 因为密码加密是以帐号+密码的形式进行加密的，所以解密后的对比是帐号+密码
        if (key.equals(userQuery.getAccount() + userQuery.getPassword())) {
            // 清除可能存在的Shiro权限信息缓存
            if (RedisUtil.exists(Constant.PREFIX_SHIRO_CACHE + userQuery.getAccount())) {
                RedisUtil.delKey(Constant.PREFIX_SHIRO_CACHE + userQuery.getAccount());
            }

            // 设置RefreshToken，时间戳为当前时间戳，直接设置即可(不用先删后设，会覆盖已有的RefreshToken)
            String currentTimeMillis = String.valueOf(System.currentTimeMillis());
            RedisUtil.setObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userQuery.getAccount(), currentTimeMillis, Integer.parseInt(refreshTokenExpireTime));
            // 从Header中Authorization返回AccessToken，时间戳为当前时间戳
            String token = JwtUtil.sign(userQuery.getAccount(), currentTimeMillis);
            httpServletResponse.setHeader("Authorization", token);
            System.out.println("token:  "+token);
            httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");

            User user=userService.getOneUserByAccount(userQuery);
            UserAllVo userAllVo= BeanUtil.copyProperties(user,UserAllVo.class);
            List<Map<String,Object>> resInfo=oracleJdbc.queryForList("select * from studentprofile where userid='"+userQuery.getAccount()+"'");
            if(!resInfo.isEmpty()){
                UserBaseInfo userBaseInfo=JSONObject.parseObject(JSON.toJSONString(resInfo.get(0)),UserBaseInfo.class);
                userAllVo.setInfo(userBaseInfo);
            }else{
                userAllVo.setInfo(new UserBaseInfo());
            }

            return new ResponseBean(HttpStatus.OK.value(), "登录成功(Login Success.)", JSONObject.toJSONString(userAllVo));
        } else {
            throw new CustomUnauthorizedException("帐号或密码错误(Account or Password Error.)");
        }
    }

    /**
     * 用户登出
     * @return 返回成功标识
     */
    @RequestMapping("/logOut")
    @LogAnnotation(module = "用户模块",operator = "登出")
    @RequiresAuthentication
    public ResponseBean logOut() {
        User user = UserUtil.getUser();
        if (RedisUtil.exists(Constant.PREFIX_SHIRO_REFRESH_TOKEN + user.getAccount())) {
            if (RedisUtil.delKey(Constant.PREFIX_SHIRO_REFRESH_TOKEN + user.getAccount())!=0) {
                return new ResponseBean(HttpStatus.OK.value(), "登出成功(Delete Success)", null);
            }
        }
        throw new CustomException("登出失败，Account不存在(Deletion Failed. Account does not exist.)");
    }

    @RequestMapping("/info")
    @LogAnnotation(module = "用户模块",operator = "当前登录的用户信息")
    @RequiresAuthentication
    public ResponseBean info() {
        // 获取当前登录用户
        User userNow = UserUtil.getUser();
        return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", JSONObject.toJSONString(userNow));
    }

    @RequestMapping("/getOneUser")
    @LogAnnotation(module = "用户模块",operator = "获取单个用户")
    @RequiresAuthentication
    public ResponseBean getOne(@Validated @RequestBody UserQuery userQuery){
        if(userQuery.getId()!=null)
            return new ResponseBean(200,"成功",JSONObject.toJSONString(userService.getById(userQuery)));
        return new ResponseBean(400,"参数错误",null);
    }

    @RequestMapping("/getAll")
    @LogAnnotation(module = "用户模块",operator = "获取所有用户")
    @RequiresAuthentication
    public ResponseBean getAll(){
        return new ResponseBean(200,"成功",JSONObject.toJSONString(userService.getAll()));
    }

    @RequestMapping("/getUserByRole")
    @LogAnnotation(module = "用户模块",operator = "根据角色获取用户")
    @RequiresAuthentication
    public ResponseBean getAllByRole(@RequestBody UserQuery userQuery){
        if(userQuery.getRoles()!=null)
            return new ResponseBean(200,"成功",JSONObject.toJSONString(userService.getAllUserByRoles(userQuery)));
        return new ResponseBean(400,"参数错误",null);
    }

    @RequestMapping("/getAllUserByAccount")
    @LogAnnotation(module = "用户模块",operator = "根据账号模糊查询")
    @RequiresAuthentication
    public ResponseBean getAllUserByAccount(@RequestBody UserQuery userQuery){
        if(userQuery.getAccount()!=null&&!userQuery.getAccount().isEmpty())
            return new ResponseBean(200,"成功",JSONObject.toJSONString(userService.getAllUserByAccount(userQuery)));
        return new ResponseBean(400,"参数错误",null);
    }

    @RequestMapping("/getOneUserByAccount")
    @LogAnnotation(module = "用户模块",operator = "根据账号精确查询")
    @RequiresAuthentication
    public ResponseBean getOneUserByAccount(@RequestBody UserQuery userQuery){
        if(userQuery.getAccount()!=null&&!userQuery.getAccount().isEmpty()){
            User user=userService.getOneUserByAccount(userQuery);
            if(user==null)
                return new ResponseBean(200,"成功",JSONObject.toJSONString(new User()));
            return new ResponseBean(200,"成功",JSONObject.toJSONString(user));
        }
        return new ResponseBean(400,"参数错误",null);
    }

    @RequestMapping("/userSearch")
    @LogAnnotation(module = "用户模块",operator = "用户查询")
    @RequiresAuthentication
    public ResponseBean userSearch(@RequestBody UserQuery userQuery){
        return new ResponseBean(200,"成功",JSONObject.toJSONString(userService.userSearch(userQuery)));
    }

    @RequestMapping("/add")
    @LogAnnotation(module = "用户模块",operator = "添加用户")
    @RequiresAuthentication
    public ResponseBean add(@Validated(value = Save.class) @RequestBody UserQuery userQuery){
        try{
            Boolean flag=userService.addUser(userQuery);
            if(flag)
                return new ResponseBean(200,"成功", true);
            return new ResponseBean(400,"用户名重复", false);
        } catch (Exception e){
            e.printStackTrace();
            logger.error("传入参数：" + userQuery + "/n" + e.getMessage());
            return new ResponseBean(500,"失败",false);
        }
    }

    @RequestMapping("/delUser")
    @LogAnnotation(module = "用户模块",operator = "删除用户")
    @RequiresAuthentication
    public ResponseBean del(@Validated(value = Del.class) @RequestBody UserQuery userQuery){
        try{
            Boolean flag=userService.deleteUserById(userQuery);
            if(flag)
                return new ResponseBean(200,"成功",true);
            return new ResponseBean(400,"用户不存在",false);
        } catch (Exception e){
            e.printStackTrace();
            logger.error("传入参数：" + userQuery + "/n" + e.getMessage());
            return new ResponseBean(500,"失败",false);
        }

    }

    @RequestMapping("/change")
    @LogAnnotation(module = "用户模块",operator = "更新用户")
    @RequiresAuthentication
    public ResponseBean update(@Validated(value = Update.class) @RequestBody UserQuery userQuery){
        try{
            Boolean flag=userService.updateUserById(userQuery);
            if(flag)
                return new ResponseBean(200,"成功",true);
            return new ResponseBean(400,"用户不存在",false);
        } catch (Exception e){
            e.printStackTrace();
            logger.error("传入参数：" + userQuery + e.getMessage());
            return new ResponseBean(500,"失败",false);
        }
    }

    @RequestMapping("/getBaseInfo")
    @LogAnnotation(module = "用户模块",operator = "获取基本信息")
    @RequiresAuthentication
    public ResponseBean getBaseInfo(@RequestParam String type){
        switch (type){
            case "unit":
                return new ResponseBean(200,"查找成功",oracleJdbc.queryForList("select unit_id,unit_name from unit"));
            case "school":
                return new ResponseBean(200,"查找成功",oracleJdbc.queryForList("select * from school"));
            default:return new ResponseBean(400,"查找失败",null);
        }
    }

    @RequestMapping("/userchange")
    @LogAnnotation(module = "用户模块",operator = "更新用户密码")
    @RequiresAuthentication
    public ResponseBean userchange(@RequestBody UserQuery userQuery){
        try{
            Boolean flag=userService.userChangePass(userQuery);
            if(flag==null)
                return new ResponseBean(400,"用户不存在",false);
            if(flag)
                return new ResponseBean(200,"成功",true);
            return new ResponseBean(1000,"旧密码输入错误",false);
        } catch (Exception e){
            e.printStackTrace();
            logger.error("传入参数：" + userQuery + e.getMessage());
            return new ResponseBean(500,"失败",false);
        }
    }

    @RequestMapping("/uploadLogo")
    @RequiresAuthentication
    public ResponseBean upload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return new ResponseBean(500,"上传失败，请选择文件",null);
        }

        File dest = new File(path + IdGenerator.uuid()+file.getOriginalFilename());
        try {
            file.transferTo(dest);
            UserQuery userQuery=new UserQuery();
            userQuery.setId(UserUtil.getUserId());
            userQuery.setPicPath("http://10.1.40.84:7878/file/"+ URLEncoder.encode(dest.getName(), "UTF-8"));
            userService.updateUserById(userQuery);
            return new ResponseBean(200,"上传成功",userQuery.getPicPath());
        } catch (IOException e) {
            return new ResponseBean(400,"上传失败",null);
        }
    }

    @RequestMapping("/DownloadReport")
    public ResponseBean DownloadReport(@RequestBody TransQuery transQuery,HttpServletResponse response) {
        try{
            return new ResponseBean(200,"下载成功",wordService.transToFile(transQuery,response));
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseBean(400,"下载失败",null);
        }
    }

    @RequestMapping("/downloadFile")
    private ResponseBean downloadFile(HttpServletResponse response,@RequestParam String fileName) throws IOException {
        // 穿件输入对象
        FileInputStream fis = new FileInputStream("/home/hadoop/attrfile/picture/"+fileName);
        // 设置下载后的文件名以及header
        response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
        response.setContentType("application/octet-stream");
        // 创建输出对象
        OutputStream os = response.getOutputStream();
        // 常规操作
        byte[] buf = new byte[1024];
        int len = 0;
        while((len = fis.read(buf)) != -1) {
            os.write(buf, 0, len);
        }
        fis.close();
        os.close();
        os.flush();
        return new ResponseBean(200,"下载成功",null);
    }
}
